<template>
  <div class="flow-x6" :id="flowId"></div>
</template>

<script>
import { Graph } from "@antv/x6";
import { register } from "@antv/x6-vue-shape";
export default {
  props: {
    /**
     * nodeComs: Array 节点组件数据
     * nodeComs.comName: String 组件名称
     */
    nodeComs: {
      type: Array,
      default: () => [],
      required: true,
    },
    /**
     * graphCfg: Object 画布配置
     * graphCfg.background: Object 画布背景配置
     * graphCfg.grid: Object 画布网格配置
     * graphCfg.interacting: Object 画布交互配置
     * graphCfg.isPanning: Boolean 是否启用画布平移功能
     * graphCfg.isCenter: Boolean 是否居中画布
     */
    graphCfg: {
      type: Object,
      default: () => {},
      required: false,
    },
    /**
     * nodeData: Array 节点数据
     * nodeData.shape: String 节点类型名称
     * nodeData.id: String 节点id
     * nodeData.x: Number 节点x坐标
     * nodeData.y: Number 节点y坐标
     * nodeData.width: Number 节点宽度
     * nodeData.height: Number 节点高度
     * nodeData.ports: Object 节点端口配置
     * nodeData.data: Object 节点参数
     * nodeData.data.width: Number 组件宽度
     * nodeData.data.height: Number 组件高度
     */
    nodeData: {
      type: Array,
      default: () => [],
      required: true,
    },
    /**
     * edgeCfg: Array 边数据
     * edgeCfg.source: String 边起始节点id
     * edgeCfg.target: String 边目标节点id
     * edgeCfg.router: Object 边路由配置
     * edgeCfg.attrs: Object 边样式配置
     */
    edgeCfg: {
      type: Array,
      default: () => [],
      required: false,
    },
  },
  data() {
    return {
      graph: null,
      importNodeComList: [],
    };
  },
  async mounted() {
    await this.importNodeComs();
    this.registerNodes();
    this.initGraph();
    this.addNodes();
    this.addEdges();
    this.initGraphShowConfig();
  },
  methods: {
    // 导入节点组件
    async importNodeComs() {
      const context = require.context(
        "@/components/JishanFlow/NodeComponents",
        false,
        /\.vue$/
      );
      const importPromises = this.nodeComs.map((item) => {
        const fileName = item.nodeName;
        const matchedModule = context(`./${fileName}.vue`);
        return {
          ...item,
          component: matchedModule.default,
        };
      });
      this.importNodeComList = await Promise.all(importPromises);
    },
    // 注册节点
    registerNodes() {
      this.importNodeComList.forEach((item) => {
        register({
          shape: item.nodeName,
          component: item.component,
        });
      });
    },
    // 初始化画布
    initGraph() {
      const { background, interacting, grid } = this.graphCfg || {};
      const defaultBackground = {
        color: "#fffbe6",
      };
      const defaultGrid = {
        size: 10, // 网格大小 10px
        visible: true, // 渲染网格背景
      };
      const defaultInteracting = {
        nodeMovable: false, // 禁止节点拖拽
      };
      this.graph = new Graph({
        container: document.getElementById(this.flowId),
        background: background || defaultBackground,
        grid: grid || defaultGrid,
        interacting: interacting || defaultInteracting,
        autoResize: true,
      });
    },
    // 初始化画布展示配置
    initGraphShowConfig() {
      const { isPanning = true, isCenter = true } = this.graphCfg || {};
      if (isPanning) {
        this.graph.enablePanning(); // 启用画布平移功能
      }
      if (isCenter) {
        this.graph.centerContent();
      }
    },
    // 新增节点
    addNodes() {
      for (const node of this.nodeData) {
        let ports = this.defaultNodePortsCfg(node);
        if ("prorts" in node) {
          ports = node.prorts;
        }
        this.graph.addNode({
          ...node,
          ports,
        });
      }
    },
    // 新增边
    addEdges() {
      if (this.edgeCfg && this.edgeCfg.length) {
        this.edgeCfg.forEach((edge) => {
          this.graph.addEdge(edge);
        });
      }
    },
    // 默认节点配置
    defaultNodePortsCfg(nodeCfg) {
      const { width, height } = nodeCfg;
      return {
        groups: {
          // 定义端口组
          in: {
            position: "top", // 输入端口在顶部
            attrs: {
              circle: {
                r: 0,
                magnet: true,
                stroke: "#31d0c6",
                strokeWidth: 0,
                fill: "#fff",
              },
            },
          },
          out: {
            position: {
              name: "absolute", // 使用绝对定位
              args: {}, // 具体位置在items中定义
            },
            attrs: {
              circle: {
                r: 0,
                magnet: true,
                stroke: "#31d0c6",
                strokeWidth: 0,
                fill: "#fff",
              },
            },
          },
        },
        items: [
          {
            id: "in-top",
            group: "in",
            args: { x: width / 2, y: 0 }, // 顶部中心
          },
          {
            id: "out-left",
            group: "out",
            args: { x: 0, y: height / 2 }, // 左侧中间
          },
          {
            id: "out-right",
            group: "out",
            args: { x: width, y: height / 2 }, // 右侧中间
          },
          {
            id: "out-bottom",
            group: "out",
            args: { x: width / 2, y: height }, // 底部中心
          },
        ],
      };
    },
  },
  computed: {
    flowId() {
      return `flow-${new Date().getTime() + Math.floor(Math.random() * 1000)}`;
    },
  },
};
</script>

<style lang="scss" scoped>
.flow-x6 {
  width: 100%;
  height: 100%;
}
</style>
